using UnityEngine;
using UnityEngine.InputSystem;
using EventBehaviorTree;
using System;
using UnityEngine.SceneManagement;
using BehaviorSystem;
using Unity.Mathematics;

public class MainRole : SingletonMonoBehaviour<MainRole>
{
    [Header("Physical Param")]
    public float _waterSpeed;
    public float _landSpeed;
    private float _currentSpeed;
    public float _jumpForce;
    public float _dashForce;
    public float _gravityScale;
    public LayerMask _groundLayer;

    private Rigidbody2D _RB;
    private int _direction;

    private bool _isInvincible;
    private Vector3 _hitDir;

    private int _jumpValidDuration;

    private Animator _animator;

    private RootNode _behaviorRoot;
    private StateSwitcher _behaviorCentral;
    private BehaviorFilter _behaviorFilter;
    private Blackboard _blackboard;

    private void Awake()
    {
        INI_Singleton();
        DontDestroyOnLoad(this);
        INI_MainRole();
    }

    private void Start()
    {
        SetUp_BehaviorSys();
    }

    private void Update()
    {
        CheckWaterSurfaceHeight();
        BehaviorValue();
    }

    private void INI_MainRole()
    {
        _RB = GetComponent<Rigidbody2D>();
        _animator = GetComponent<Animator>();
        _RB.gravityScale = _gravityScale;
        _isInvincible = false;
    }

    private void SetUp_BehaviorSys()
    {
        InputManager.Instance.Reg_InputEvent(InputActionPhase.Started, delegate (Vector2 vector2) { Move(vector2); });
        InputManager.Instance.Reg_InputEvent(InputActionPhase.Performed, delegate (Vector2 vector2) { Move(vector2); });
        InputManager.Instance.Reg_InputEvent(InputActionPhase.Canceled, delegate (Vector2 vector2) { Move(vector2); });

        _blackboard = new();
        _behaviorFilter = new();
        _behaviorRoot = new("MRB", this);//MainRoleBehavior
        _behaviorCentral = new(NodeMsgBuilder.GEN_MsgPairs("Start/Succeed"));
        _behaviorRoot.AddSubNode(_behaviorCentral);

        BehaviorBuilder.Reg_BehaviorInfo(GetType().ToString(), _behaviorFilter, ActivateBehavior);
        BehaviorBuilder.Reg_BehaviorNodes(this, _behaviorCentral);
        BlackboardHelper.Reg_BlackboardKV("BehaviorAssets.xml", $"/Behavior/{GetType()}/BlackboardValue/Value", _blackboard);

        _behaviorRoot.NodeEvent(NodeMsg.Start);
    }

    private void BehaviorValue()
    {
        _behaviorFilter.CoolDown();
        if (_behaviorFilter._currentBehavior == "")
        {
            ActivateBehavior("Idle");
        }
        if (_direction == 0)
        {
            _blackboard.Set("Move", false);
            ActivateBehavior("Idle");
        }
        else
        {
            _blackboard.Set("Idle", false);
            ActivateBehavior("Move");
        }
        if (IsOnGround())
        {
            _jumpValidDuration = 20;
            if (!_blackboard.Get<bool>("JumpValidDuration")) _blackboard.Set("JumpValidDuration", true);
            if (!_blackboard.Get<bool>("DashValid")) _blackboard.Set("DashValid", true);
        }
        if (IsInAir())
        {
            _jumpValidDuration = math.max(--_jumpValidDuration, 0);
            if (_blackboard.Get<bool>("JumpValidDuration") && _jumpValidDuration == 0) _blackboard.Set("JumpValidDuration", false);
        }
    }

    private void ActivateBehavior(string key)
    {
        if (_behaviorFilter.IsPermitted(key))
        {
            _blackboard.Set(key, true);//the condition to enter this behavior
            _behaviorFilter.Deactivate();//interrupt current behavior
            _behaviorFilter.ActiveBehavior(key);//the condition to interrupt the behavior
        }
    }

    private void CheckWaterSurfaceHeight()
    {
        if (gameObject.transform.position.y < AirCurtain.Instance.transform.position.y)
        {
            _currentSpeed = _waterSpeed;
        }
        else
        {
            _currentSpeed = _landSpeed;
        }
    }

    #region Behavior
    private void BBSet<T>(string key, T value) { _blackboard.Set(key, value); }
    private void Dash()
    {
        Vector2 vector2 = new Vector2(gameObject.transform.localScale.x == 1 ? 1 : -1, 0);
        _RB.AddForce(vector2 * _dashForce, ForceMode2D.Impulse);
    }
    private void XAxisMove()
    {
        if (_direction == 0)
        {
            _RB.velocity = new Vector3(0, _RB.velocity.y, 0);
            return;
        }
        _RB.velocity = new Vector3(Math.Abs(_direction) / _direction * _currentSpeed, _RB.velocity.y, 0);
        int dir = Math.Abs(_direction) / _direction;
        gameObject.transform.localScale = new Vector3(dir, 1, 1);//flip
    }
    private void Move(Vector2 direction) { _direction = direction.x == 0 ? 0 : ((int)(Math.Abs(direction.x) / direction.x)); }
    private void XAxisVelocity()
    {
        _RB.velocity = new Vector3(_RB.velocity.x, 0, 0);
    }
    private void Jump() { _RB.AddForce(new Vector2(_direction, 1) * _jumpForce, ForceMode2D.Impulse); }
    private void NoGravity() { _RB.gravityScale = 0; }
    private void ResetGravity() { _RB.gravityScale = _gravityScale; }
    private void Stop() { _RB.velocity = Vector3.zero; }
    private void Invincible() { _isInvincible = true; }
    private void Defenceless() { _isInvincible = false; }
    private void TakeDamage(float pushForceByHit) { _RB.AddForce(_hitDir * pushForceByHit, ForceMode2D.Impulse); }
    private void Load() { SaveLoadManager.Instance.Load(); }
    private void Deactivate() { _behaviorFilter.Deactivate(); }
    #endregion
    #region Condition
    private bool IsOnGround()
    {
        bool result = Physics2D.OverlapArea((Vector2)transform.position + new Vector2(-0.18f, -0.6f), (Vector2)transform.position + new Vector2(0.18f, -0.7f), _groundLayer);
        return result;
    }
    private bool IsInAir() { return !IsOnGround(); }
    private bool IsInvincible() { return _isInvincible; }
    private bool IsDefenceless() { return !_isInvincible; }
    private bool IsBehaviorActive(string key) { return _behaviorFilter.IsBehaviorActive(key); }
    private bool IsBehaviorDeactive(string key) { return !_behaviorFilter.IsBehaviorActive(key); }
    private bool IsBBCompare(string boolKey) { return _blackboard.Get<bool>(boolKey); }
    #endregion
    #region Anim
    private void Anim_Idle() { _animator.Play("Squid_Idle"); }
    private void Anim_Run() { _animator.Play("Squid_Run"); }
    private void Anim_Jump() { _animator.Play("Squid_Jump"); }
    private void Anim_Die() { _animator.Play("Squid_Die"); }
    private void Anim_Dash() { _animator.Play("Squid_Dash"); }
    private void Anim_Fall() { _animator.Play("Squid_Fall"); }
    #endregion

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.transform.tag == "Trap")
        {
            _hitDir = new Vector3(UnityEngine.Random.Range(0.6f, 0.9f) * _direction * -1f, UnityEngine.Random.Range(0.6f, 0.9f), 0);
            if (IsDefenceless()) ActivateBehavior("Hit");
        }
        if (collision.transform.tag == "Complete")
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
            GameManager.Instance.GameComplete();
        }
        if (collision.transform.tag == "CameraRelocation")
        {
            CameraController.Instance.ChangeTarget(collision.GetComponent<CameraRelocation>()._position);
        }
    }
    private void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.transform.tag == "CameraRelocation")
        {
            CameraController.Instance.ChangeTarget(gameObject);
        }
    }
    private void OnTriggerStay2D(Collider2D collision)
    {
        if (collision.transform.tag == "Trap")
        {
            _hitDir = new Vector3(UnityEngine.Random.Range(0.6f, 0.9f) * _direction * -1f, UnityEngine.Random.Range(0.6f, 0.9f), 0);
            if (IsDefenceless()) ActivateBehavior("Hit");
        }
    }

    //private bool IsBBCompare(string lhsKey, string rhsKey, CmprOP cmprOP)
    //{
    //    return _blackboard.Compare(lhsKey, rhsKey, cmprOP);
    //}
    //private bool IsBBCompare(string boolKey, CmprOP cmprOP)
    //{
    //    return _blackboard.Compare(boolKey, cmprOP);
    //}
}
